﻿using Microsoft.EntityFrameworkCore;
using Restful_Api.Data;
using Restful_Api.DtoParameters;
using Restful_Api.Entities;
using Restful_Api.Helpers;
using Restful_Api.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Restful_Api.Services
{
    public class CompanyRepository : ICompanyRepository
    {
        private readonly RoutineDbContext _context;
        private readonly IPropertyMappingService propertyMapping;

        public CompanyRepository(RoutineDbContext context, IPropertyMappingService  propertyMapping)
        {
            _context = context ?? throw new ArgumentNullException(nameof(context));
            this.propertyMapping = propertyMapping;
        }

        public void AddCompany(Company company)
        {
            if (company == null)
                throw new ArgumentNullException(nameof(company));
            company.Id = Guid.NewGuid();
            if (company.Employees != null)
            {
                foreach (var item in company.Employees)
                {
                    item.Id = Guid.NewGuid();
                }
            }

            _context.Companies.Add(company);
        }

        public void AddEmployee(Guid companyId, Employee employee)
        {
            if (companyId == Guid.Empty)
                throw new ArgumentNullException(nameof(companyId));
            if (employee == null)
                throw new ArgumentNullException(nameof(employee));
            employee.CompanyId = companyId;
            _context.Employees.Add(employee);

        }

        public async Task<bool> CompanyExistsAsync(Guid companyId)
        {
            if (companyId == Guid.Empty)
                throw new ArgumentNullException(nameof(companyId));

            return await _context.Companies.AnyAsync(x => x.Id == companyId);
        }

        public void DeleteCompany(Company company)
        {
            if (company == null)
                throw new ArgumentNullException(nameof(company));
            _context.Companies.Remove(company);
        }

        public void DeleteEmployee(Employee employee)
        {
            _context.Employees.Remove(employee);
        }        

        public async Task<PageList<Company>> GetCompaniesAsync(CompanyDtoParameters parameters)
        {
            if (parameters == null)
                throw new ArgumentNullException(nameof(parameters));
            
            var queryExpression = _context.Companies as IQueryable<Company>;
            if (!string.IsNullOrWhiteSpace(parameters.CompanyName))
                queryExpression = queryExpression.Where(x => x.Name == parameters.CompanyName);
            if (!string.IsNullOrWhiteSpace(parameters.SearchTerm))
                queryExpression = queryExpression.Where(x => x.Name.Contains(parameters.SearchTerm) || x.Introduction.Contains(parameters.SearchTerm));


            var mappingDictionary = propertyMapping.GetPropertyMapping<CompanyDto, Company>();
            queryExpression = queryExpression.ApplySort(parameters.OrderBy, mappingDictionary);

            return await PageList<Company>.CreateAsync(queryExpression, parameters.PageNum,parameters.PageSize);
        }

        public async Task<IEnumerable<Company>> GetCompaniesAsync(IEnumerable<Guid> companyids)
        {
            if (companyids == null)
                throw new ArgumentNullException(nameof(companyids));
            return await _context.Companies
                .Where(x => companyids.Contains(x.Id))
                .OrderBy(x => x.Name)
                .ToListAsync();

        }

        public async Task<Company> GetCompanyAsync(Guid companyid)
        {
            if (companyid == Guid.Empty)
                throw new ArgumentNullException(nameof(companyid));          
            return await _context.Companies.Include(x => x.Employees)
                .FirstOrDefaultAsync(x => x.Id == companyid);
        }

        public async Task<Employee> GetEmployeeAsync(Guid companyId, Guid employeeId)
        {
            if (companyId == Guid.Empty)
                throw new ArgumentNullException(nameof(companyId));
            if (employeeId == Guid.Empty)
                throw new ArgumentNullException(nameof(employeeId));
            return await _context.Employees
                .Where(x => x.CompanyId == companyId && x.Id == employeeId)
                .FirstOrDefaultAsync();
        }

        public async Task<IEnumerable<Employee>> GetEmployeesAsync(Guid companyId, EmployeeDtoParameters parameters)
        {
            if (companyId == Guid.Empty)
                throw new ArgumentNullException(nameof(companyId));

            var items = _context.Employees.Where(x => x.CompanyId == companyId);

            if (!string.IsNullOrWhiteSpace(parameters.Gender))
            {
                var gender = Enum.Parse<Gender>(parameters.Gender.Trim());
                items = items.Where(x => x.Gender == gender);
            }
            if (!string.IsNullOrWhiteSpace(parameters.Q))
            {
                parameters.Q = parameters.Q.Trim();
                items = items.Where(x => x.EmployeeNo.Contains(parameters.Q) || x.FistName.Contains(parameters.Q) || x.LastName.Contains(parameters.Q));
            }

            var mappingDictionay = propertyMapping.GetPropertyMapping<EmployeeDto, Employee>();
            //applySort是自定义的拓展方法在IQueryableExtensions
            items= items.ApplySort(parameters.OrderBy, mappingDictionay);
            return await items.ToListAsync();
        }

        public async Task<bool> SaveAsync()
        {
            return await _context.SaveChangesAsync() >= 0;
        }

        public void UpdataCompany(Company company)
        {
            throw new NotImplementedException();
        }

        public void UpdataEmployee(Employee employee)
        {        
            //context会自动的跟踪更新
        }            
    }
}
